﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.ShprossesBuilder.Modelling.Components;
using ITAP.ShprossesBuilder.Editor;
using ITAP.ShprossesBuilder.Modelling;
using ITAP.ShprossesBuilder.Properties;
using ITAP.Core.Modelling;

namespace ITAP.ShprossesBuilder.Operations
{
    public class OperationDisperseShprossConnectors : IOperation
    {
        #region IOperation Members

        public string Name
        {
            get { return "Скопировать и разнести коннекторы"; }
        }

        public OperationGroup OperationGroup
        {
            get { return OperationGroup.ShprossConnectorOperation; }
        }

        public System.Drawing.Image Thumbnail
        {
            get { return Resources.Disperse.ToBitmap(); }
        }

        public void Execute(ModelControl modelControl)
        {
            if(modelControl.ModelContainer.SelectedComponentsStack.Count == 0)
                return;


            ShprossConnectorType type = ShprossConnectorType.Undefined;
            List<ShprossConnector> shprossConnectors = new List<ShprossConnector>();
            foreach (IComponent selectedComponent in modelControl.ModelContainer.SelectedComponentsStack)
            {
                ShprossConnector connector = selectedComponent as ShprossConnector;
                if (connector == null)
                    continue;

                if(type == ShprossConnectorType.Undefined)
                    type = connector.ShprossConnectorType;

                if (type != connector.ShprossConnectorType)
                    return;
                shprossConnectors.Add(selectedComponent as ShprossConnector);
            }

            DisperseShprossConnectorForm form = new DisperseShprossConnectorForm(type);
            if (form.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;
            Shpross shpross = null;
            if (form.Disperse == DisperseTo.DiamondWithShprosses || form.Disperse == DisperseTo.RectangleWithShprosses)
            {
                SelectMaterialForm material = new SelectMaterialForm();
                material.Initialize(modelControl.ProfileProvider, new Material[] { Material.Shpross }, false, "Выберите профиль", false);
                if (material.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                    return;
                shpross = material.SelectedComponent as Shpross;
            }

            Model model = null;
            foreach (ShprossConnector connector in shprossConnectors)
            {
                    model = connector.Parent as Model;
                    this.Disperse(connector, form.Disperse, form.Distance, shpross);
                    if (form.DeleteParentShprossConnector)
                        model.RemoveInnerComponent(connector);
            }
        }

        private void Disperse(ShprossConnector connector, DisperseTo disperse, double distance, Shpross shprossPrototype)
        {
            switch (disperse)
            {
                case DisperseTo.Diamond:
                    this.DisperseToDiamond(connector, distance);
                    break;
                case DisperseTo.Rectangle:
                    this.DisperseToRectangle(connector, distance);
                    break;
                case DisperseTo.RectangleWithShprosses:
                    this.DisperseToRectangleWithShprosses(connector, shprossPrototype, distance);
                    break;
                case DisperseTo.DiamondWithShprosses:
                    this.DisperseToDiamondWithShprosses(connector, distance, shprossPrototype); 
                    break;
            }
        }

        private void DisperseToRectangle(ShprossConnector connector, double distance)
        {            
            Model model = connector.Parent as Model;

            ModelVector toUpRight = new ModelVector(distance, distance);
            ModelVector toUpLeft = new ModelVector(-distance, distance);
            ModelVector toDownLeft = new ModelVector(-distance, -distance);
            ModelVector toDownRight = new ModelVector(distance, -distance);

            ShprossConnector upRight = connector.Copy() as ShprossConnector;
            upRight.SerialNumber = 0;
            upRight.MoveWithOffset(toUpRight, model.BoundingBox);

            ShprossConnector upLeft = connector.Copy() as ShprossConnector;
            upLeft.SerialNumber = 0;
            upLeft.MoveWithOffset(toUpLeft, model.BoundingBox);

            ShprossConnector downLeft = connector.Copy() as ShprossConnector;
            downLeft.SerialNumber = 0;
            downLeft.MoveWithOffset(toDownLeft, model.BoundingBox);

            ShprossConnector downRight = connector.Copy() as ShprossConnector;
            downRight.SerialNumber = 0;
            downRight.MoveWithOffset(toDownRight, model.BoundingBox);

            model.AddInnerComponent(upRight);
            model.AddInnerComponent(upLeft);
            model.AddInnerComponent(downLeft);
            model.AddInnerComponent(downRight);
        }

        private void DisperseToDiamond(ShprossConnector connector, double distance)
        {
            Model model = connector.Parent as Model;

            ModelVector toRight = new ModelVector(distance, 0);
            ModelVector toUp = new ModelVector(0, distance);
            ModelVector toLeft = new ModelVector(-distance, 0);
            ModelVector toDown = new ModelVector(0, -distance);

            ShprossConnector right = connector.Copy() as ShprossConnector;
            right.SerialNumber = 0;
            right.MoveWithOffset(toRight, model.BoundingBox);

            ShprossConnector left = connector.Copy() as ShprossConnector;
            left.SerialNumber = 0;
            left.MoveWithOffset(toLeft, model.BoundingBox);

            ShprossConnector up = connector.Copy() as ShprossConnector;
            up.SerialNumber = 0;
            up.MoveWithOffset(toUp, model.BoundingBox);

            ShprossConnector down = connector.Copy() as ShprossConnector;
            down.SerialNumber = 0;
            down.MoveWithOffset(toDown, model.BoundingBox);

            model.AddInnerComponent(right);
            model.AddInnerComponent(up);
            model.AddInnerComponent(left);
            model.AddInnerComponent(down);
        }

        private void DisperseToRectangleWithShprosses(ShprossConnector connector, Shpross shprossPrototype, double distance)
        {
            if (connector.ShprossConnectorType != ShprossConnectorType.X)
                return;

            Model model = connector.Parent as Model;

            ModelVector toUpRight = new ModelVector(distance, distance);
            ModelVector toUpLeft = new ModelVector(-distance, distance);
            ModelVector toDownLeft = new ModelVector(-distance, -distance);
            ModelVector toDownRight = new ModelVector(distance, -distance);

            ShprossConnector upRight = connector.Copy() as ShprossConnector;
            upRight.SerialNumber = 0;
            upRight.MoveWithOffset(toUpRight, model.BoundingBox);

            ShprossConnector upLeft = connector.Copy() as ShprossConnector;
            upLeft.SerialNumber = 0;
            upLeft.MoveWithOffset(toUpLeft, model.BoundingBox);

            ShprossConnector downLeft = connector.Copy() as ShprossConnector;
            downLeft.SerialNumber = 0;
            downLeft.MoveWithOffset(toDownLeft, model.BoundingBox);

            ShprossConnector downRight = connector.Copy() as ShprossConnector;
            downRight.SerialNumber = 0;
            downRight.MoveWithOffset(toDownRight, model.BoundingBox);

            if (shprossPrototype != null)
            {
                Shpross shprossRight = shprossPrototype.Copy() as Shpross;
                shprossRight.SerialNumber = 0;
                model.AddInnerComponent(shprossRight);
                Shpross shprossUp = shprossPrototype.Copy() as Shpross;
                shprossUp.SerialNumber = 0;
                model.AddInnerComponent(shprossUp);
                Shpross shprossLeft = shprossPrototype.Copy() as Shpross;
                shprossLeft.SerialNumber = 0;
                model.AddInnerComponent(shprossLeft);
                Shpross shprossDown = shprossPrototype.Copy() as Shpross;
                shprossDown.SerialNumber = 0;
                model.AddInnerComponent(shprossDown);

                shprossRight.MoveStartPointTo(upRight[3].StartPoint);
                shprossRight.MoveEndPointTo(downRight[1].StartPoint);

                shprossUp.MoveStartPointTo(upLeft[0].StartPoint);
                shprossUp.MoveEndPointTo(upRight[2].StartPoint);

                shprossLeft.MoveStartPointTo(downLeft[1].StartPoint);
                shprossLeft.MoveEndPointTo(upLeft[3].StartPoint);

                shprossDown.MoveStartPointTo(downRight[2].StartPoint);
                shprossDown.MoveEndPointTo(downLeft[0].StartPoint);
            }

            model.AddInnerComponent(upRight);
            model.AddInnerComponent(upLeft);
            model.AddInnerComponent(downLeft);
            model.AddInnerComponent(downRight);
        }

        private void DisperseToDiamondWithShprosses(ShprossConnector connector, double distance, Shpross shprossPrototype)
        {
            if (connector.ShprossConnectorType != ShprossConnectorType.Y)
                return;

            Model model = connector.Parent as Model;

            ModelVector toRight = new ModelVector(distance, 0);
            ModelVector toUp = new ModelVector(0, distance);
            ModelVector toLeft = new ModelVector(-distance, 0);
            ModelVector toDown = new ModelVector(0, -distance);

            ShprossConnector right = connector.Copy() as ShprossConnector;
            right.SerialNumber = 0;
            right.Angle = new Angle(-Math.PI / 2);
            right.MoveWithOffset(toRight, model.BoundingBox);

            ShprossConnector left = connector.Copy() as ShprossConnector;
            left.SerialNumber = 0;
            left.MoveWithOffset(toLeft, model.BoundingBox);
            left.Angle = new Angle(Math.PI / 2);

            ShprossConnector up = connector.Copy() as ShprossConnector;
            up.SerialNumber = 0;
            up.MoveWithOffset(toUp, model.BoundingBox);
            up.Angle = new Angle(0);

            ShprossConnector down = connector.Copy() as ShprossConnector;
            down.SerialNumber = 0;
            down.MoveWithOffset(toDown, model.BoundingBox);
            down.Angle = new Angle(Math.PI);

            if(shprossPrototype != null)
            {
                Shpross shprossRightUp = shprossPrototype.Copy() as Shpross;
                shprossRightUp.SerialNumber = 0;
                model.AddInnerComponent(shprossRightUp);
                Shpross shprossUpLeft = shprossPrototype.Copy() as Shpross;
                shprossUpLeft.SerialNumber = 0;
                model.AddInnerComponent(shprossUpLeft);
                Shpross shprossLeftDown = shprossPrototype.Copy() as Shpross;
                shprossLeftDown.SerialNumber = 0;
                model.AddInnerComponent(shprossLeftDown);
                Shpross shprossDownRight = shprossPrototype.Copy() as Shpross;
                shprossDownRight.SerialNumber = 0;
                model.AddInnerComponent(shprossDownRight);

                shprossRightUp.MoveStartPointTo(right[1].StartPoint);
                shprossRightUp.MoveEndPointTo(up[2].StartPoint);

                shprossUpLeft.MoveStartPointTo(up[1].StartPoint);
                shprossUpLeft.MoveEndPointTo(left[2].StartPoint);

                shprossLeftDown.MoveStartPointTo(left[1].StartPoint);
                shprossLeftDown.MoveEndPointTo(down[2].StartPoint);

                shprossDownRight.MoveStartPointTo(down[1].StartPoint);
                shprossDownRight.MoveEndPointTo(right[2].StartPoint);
            }
            model.AddInnerComponent(right);
            model.AddInnerComponent(up);
            model.AddInnerComponent(left);
            model.AddInnerComponent(down);
        }

        public bool CanUndo
        {
            get { return true; }
        }

        #endregion
    }
}
